﻿// ....................................................................................................................
//	Author: Copyright (C) 2012 Ing. Marek Hubal
//	Email: hubal@acasoftware.org
// ....................................................................................................................

using System;

namespace core
{
    /// <summary>Trieda INodeList_SMB_NETWORK</summary>
    public class INodeList_SMB_NETWORK : INodeList
    {
        /// <summary>Trieda IExpandInfo</summary>
        protected class IExpandInfo : IDisposable
        {
            public IWin32.NETRESOURCE Resource;
            public IWin32.ErrorCodes ResultCode;
            public IntPtr Handle;
            public IntPtr MemoryHandle;
            public uint Entries;
            public uint BufferSize;

            /// <summary>Konstruktor</summary>
            /// <param name="pItem">inicializacna hodnota</param>
            public IExpandInfo(IExpandInfo pItem = null)
            {
                Resource = new IWin32.NETRESOURCE();
                ResultCode = IWin32.ErrorCodes.NO_ERROR;
                if (pItem != null) // Skopirovat data?
                {
                    Resource.dwScope = pItem.Resource.dwScope;
                    Resource.dwType = pItem.Resource.dwType;
                    Resource.dwDisplayType = pItem.Resource.dwDisplayType;
                    Resource.dwUsage = pItem.Resource.dwUsage;
                    Resource.lpLocalName = pItem.Resource.lpLocalName;
                    Resource.lpRemoteName = pItem.Resource.lpRemoteName;
                    Resource.lpComment = pItem.Resource.lpComment;
                    Resource.lpProvider = pItem.Resource.lpProvider;
                }
                Handle = IntPtr.Zero;
                Entries = 1;
                BufferSize = 16384;
                MemoryHandle = System.Runtime.InteropServices.Marshal.AllocHGlobal((int)BufferSize); // Alokujem pamat
            }

            /// <summary>Dispose metoda</summary>
            public void Dispose()
            {
                if (Handle != IntPtr.Zero) IWin32.Mpr.WNetCloseEnum(Handle); // Uzatvorim handle hladania
                if (MemoryHandle != IntPtr.Zero) System.Runtime.InteropServices.Marshal.FreeHGlobal(MemoryHandle); // Uvolnim pamat
                Handle = IntPtr.Zero;
                MemoryHandle = IntPtr.Zero;
            }
        }

        protected System.Collections.Generic.List<IExpandInfo> FExpand_Items;

        /// <summary>Zapis node do cache</summary>
        /// <param name="pNode">objekt</param>
        protected override void WriteNodeToCache(INode pNode)
        {
            if (!IsWriteCacheReady) return; // Ziadna cache?

            FCacheWriter.Write(pNode.ID);
            FCacheWriter.Write(((INodeData_SMB_COMPUTER)pNode.NodeData).ComputerName);
            FCacheWriter.Write(((INodeData_SMB_COMPUTER)pNode.NodeData).ComputerComment);
        }
        /// <summary>Nacitanie node z cache</summary>
        /// <returns>objekt alebo null pre koniec</returns>
        protected override bool ReadNodeFromCache(INode Result)
        {
            if (!IsReadCacheReady) return false;
            try
            {
                Result.ID = FCacheReader.ReadInt32(); // Nacitam
                Result.NodeData = new INodeData_SMB_COMPUTER();
                ((INodeData_SMB_COMPUTER)Result.NodeData).ComputerName = FCacheReader.ReadString();
                ((INodeData_SMB_COMPUTER)Result.NodeData).ComputerComment = FCacheReader.ReadString();
                return true; // Vsetko OK
            }
            catch
            {
                return false;
            }
        }

        /// <summary>Konstruktor</summary>
        public INodeList_SMB_NETWORK()
        {
            // Inicializacia
            ID = NODE_LIST_ID_SMB_NETWORK;
            FColsCount = 2;
            FEnableVisibilityMask = 0x2; FDefVisibilityMask = 0x3;
        }

        /// <summary>Ziskanie nazvu stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>nazov alebo prazdny retazec</returns>
        public override string GetColumnName(int pIndex)
        {
            switch (pIndex)
            {
                case 0: return lang.NODE_LIST_SMB_NETWORK_TEXT_1;
                case 1: return lang.NODE_LIST_SMB_NETWORK_TEXT_2;
                default: return "";
            }
        }

        /// <summary>Property: CurrentPath</summary>
        public override string CurrentPath
        {
            get
            {
                return "\\\\";
            }
        }
        /// <summary>Property: KeyValue</summary>
        public override string KeyValue
        {
            get
            {
                return "\\\\";
            }
        }
        /// <summary>Property: IsSlowDevice</summary>
        public override bool IsSlowDevice
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test ci sa node moze expandovat</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanNodeExpand(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_SMB_COMPUTER:
                    return true;
                default: return false;
            }
        }
        /// <summary>Ziskanie expandovacej cesty node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>cesta</returns>
        public override string GetNodeExpandPath(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return ""; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_SMB_COMPUTER: return "\\\\" + ((INodeData_SMB_COMPUTER)N.NodeData).ComputerName;
                default: return "";
            }
        }

        /// <summary>Zaciatok expandovania obsahu</summary>
        /// <param name="pFilter">objekt filtra</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int BeginExpand(INodeFilters pFilter = null)
        {
            FExpand_Items = null;
            FState = 1; // Nastavim mode expand
            return 0;
        }
        /// <summary>Uzatvorenie aktualneho expandu</summary>
        public override void CloseExpand()
        {
            if (FExpand_Items == null) return; // Nic na uvolnenie?
            for (int i = 0; i < FExpand_Items.Count; i++) FExpand_Items[i].Dispose();
            FExpand_Items.Clear(); FExpand_Items = null;
            FState = 0; // Nastavim normalny mod
        }
        /// <summary>Expandovanie dalsieho zaznamu</summary>
        /// <param name="Result">ulozeny obsah najdeneho zaznamu alebo null ak sa ma zaznam pripojit do zoznamu</param>
        /// <returns>0 - ziaden dalsi zaznam, 1 - najdeny zaznam alebo kod chyby</returns>
        public override int ExpandNext(INodeFilters pFilter = null, INode Result = null)
        {
            try
            {
                if (FExpand_Items == null)
                {
                    if ((Result == null) && (FItems.Count == 0)) { INode N1 = new INode(); N1.ID = INode.NODE_ID_BACK_ITEM; AddNode(N1); } // Vytvorim prvy back item node

                    if (IsReadCacheReady)
                    {
                        INode N = Result == null ? new INode() : Result;
                        if (ReadNodeFromCache(N))
                        {
                            if (Result == null) AddNode(N);
                            WriteNodeToCache(N);
                            FCachedContent = true;
                            return 1;
                        }
                        return 0;
                    }

                    FExpand_Items = new System.Collections.Generic.List<IExpandInfo>();
                    FExpand_Items.Add(new IExpandInfo());

                    FExpand_Items[0].Resource.dwDisplayType = IWin32.ResourceDisplayType.RESOURCEDISPLAYTYPE_NETWORK; // Zaciatok hladania
                    FExpand_Items[0].Resource.dwScope = IWin32.ResourceScope.RESOURCE_GLOBALNET;
                    FExpand_Items[0].Resource.dwType = IWin32.ResourceType.RESOURCETYPE_ANY;
                    FExpand_Items[0].Resource.dwUsage = IWin32.ResourceUsage.RESOURCEUSAGE_CONTAINER_1;
                    FExpand_Items[0].Resource.lpRemoteName = "Microsoft Windows Network";
                    FExpand_Items[0].Resource.lpProvider = "Microsoft Windows Network";

                    if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_SMB_NETWORK_TEXT_5, FItems.Count - 1);

                    // Otvorim zaciatok
                    FExpand_Items[FExpand_Items.Count - 1].ResultCode = IWin32.Mpr.WNetOpenEnum(IWin32.ResourceScope.RESOURCE_GLOBALNET, IWin32.ResourceType.RESOURCETYPE_DISK, IWin32.ResourceUsage.RESOURCEUSAGE_ALL, FExpand_Items[FExpand_Items.Count - 1].Resource, out FExpand_Items[FExpand_Items.Count - 1].Handle);
                    if (FExpand_Items[FExpand_Items.Count - 1].ResultCode != IWin32.ErrorCodes.NO_ERROR)
                    {
                        switch ((uint)FExpand_Items[FExpand_Items.Count - 1].ResultCode)
                        {
                            case IWin32.ERROR_NO_NETWORK:
                            case IWin32.ERROR_EXTENDED_ERROR:
                                LastError = lang.NODE_LIST_SMB_NETWORK_TEXT_6; break;
                        }
                        return -1; // Chyba?
                    }
                }

                if (IsReadCacheReady)
                {
                    INode N = Result == null ? new INode() : Result;
                    if (ReadNodeFromCache(N))
                    {
                        if (Result == null) AddNode(N);
                        WriteNodeToCache(N);
                        FCachedContent = true;
                        return 1;
                    }
                    return 0;
                }

                while (true)
                {
                    if (FExpand_Items[FExpand_Items.Count - 1].ResultCode == IWin32.ErrorCodes.ERROR_NO_MORE_ITEMS) // Ziadne dalsie zaznamy v aktualnej urovni?
                    {
                        FExpand_Items[FExpand_Items.Count - 1].Dispose(); // Uvolnim objekt
                        FExpand_Items.RemoveAt(FExpand_Items.Count - 1); // Znizim uroven
                        if (FExpand_Items.Count == 0) return 0; // Posledna?
                    }

                    if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_SMB_NETWORK_TEXT_5, FItems.Count - 1);

                    // Nejaka chyba?
                    if ((FExpand_Items[FExpand_Items.Count - 1].ResultCode != IWin32.ErrorCodes.NO_ERROR) && (FExpand_Items[FExpand_Items.Count - 1].ResultCode != IWin32.ErrorCodes.ERROR_NO_MORE_ITEMS))
                    {
                        FExpand_Items[FExpand_Items.Count - 1].ResultCode = IWin32.ErrorCodes.ERROR_NO_MORE_ITEMS; // Ukoncim hladanie na urovni
                        continue;
                    }

                    // Ziskam dalsi zaznam
                    FExpand_Items[FExpand_Items.Count - 1].ResultCode = IWin32.Mpr.WNetEnumResource(FExpand_Items[FExpand_Items.Count - 1].Handle, ref FExpand_Items[FExpand_Items.Count - 1].Entries, FExpand_Items[FExpand_Items.Count - 1].MemoryHandle, ref FExpand_Items[FExpand_Items.Count - 1].BufferSize);

                    if (FExpand_Items[FExpand_Items.Count - 1].ResultCode == IWin32.ErrorCodes.NO_ERROR) // Je to OK?
                    {
                        System.Runtime.InteropServices.Marshal.PtrToStructure(FExpand_Items[FExpand_Items.Count - 1].MemoryHandle, FExpand_Items[FExpand_Items.Count - 1].Resource); // Prevediem na data do struktury
                        if (FExpand_Items[FExpand_Items.Count - 1].Resource.dwDisplayType == IWin32.ResourceDisplayType.RESOURCEDISPLAYTYPE_SERVER) // Je to pocitac?
                        {
                            INode N = Result == null ? new INode() : Result;
                            N.ID = INode.NODE_ID_SMB_COMPUTER;
                            N.NodeData = new INodeData_SMB_COMPUTER();
                            ((INodeData_SMB_COMPUTER)N.NodeData).ComputerName = FExpand_Items[FExpand_Items.Count - 1].Resource.lpRemoteName;
                            if (((INodeData_SMB_COMPUTER)N.NodeData).ComputerName.StartsWith("\\\\")) ((INodeData_SMB_COMPUTER)N.NodeData).ComputerName = ((INodeData_SMB_COMPUTER)N.NodeData).ComputerName.Substring(2);
                            ((INodeData_SMB_COMPUTER)N.NodeData).ComputerComment = FExpand_Items[FExpand_Items.Count - 1].Resource.lpComment;
                            if (Result == null) AddNode(N);
                            WriteNodeToCache(N);
                            return 1;
                        }
                        else
                        {
                            if ((FExpand_Items[FExpand_Items.Count - 1].Resource.dwUsage & IWin32.ResourceUsage.RESOURCEUSAGE_CONTAINER) == IWin32.ResourceUsage.RESOURCEUSAGE_CONTAINER) // Je to kontainer?
                            {
                                FExpand_Items.Add(new IExpandInfo(FExpand_Items[FExpand_Items.Count - 1])); // Pridam dalsiu uroven
                                // Otvorim hladanie
                                FExpand_Items[FExpand_Items.Count - 1].ResultCode = IWin32.Mpr.WNetOpenEnum(IWin32.ResourceScope.RESOURCE_GLOBALNET, IWin32.ResourceType.RESOURCETYPE_DISK, IWin32.ResourceUsage.RESOURCEUSAGE_ALL, FExpand_Items[FExpand_Items.Count - 1].Resource, out FExpand_Items[FExpand_Items.Count - 1].Handle);
                                if (FExpand_Items[FExpand_Items.Count - 1].ResultCode != IWin32.ErrorCodes.NO_ERROR) FExpand_Items[FExpand_Items.Count - 1].ResultCode = IWin32.ErrorCodes.ERROR_NO_MORE_ITEMS;
                            }
                        }
                    }
                }
            }
            catch
            {
                return -1; // Neocakavana chyba
            }
        }
        /// <summary>Vytvorenie klonu zoznamu</summary>
        /// <returns>objekt zoznamu</returns>
        public override INodeList CloneList()
        {
            return new INodeList_SMB_NETWORK();
        }

        /// <summary>Vytvorenie textov pre zobrazenie</summary>
        /// <param name="pNode">objekt node</param>
        public override void CreateDisplayStrings(INode pNode)
        {
            if (pNode.DisplayStrings != null) return; // Uz su vytvorenie?

            pNode.DisplayStrings = new string[ColsCount]; // Alokujem retazec
            switch (pNode.ID) // Podla typu node
            {
                case INode.NODE_ID_BACK_ITEM:
                    {
                        pNode.DisplayStrings[0] = ICore.BoundString("[", "..", "]", IApp.Settings.FileExplorer_DirsInBraces);
                        pNode.DisplayStrings[1] = lang.NODE_LIST_SMB_NETWORK_TEXT_4;
                        pNode.DefaultImageIndex = -1;
                    } break;
                case INode.NODE_ID_SMB_COMPUTER:
                    {
                        pNode.DisplayStrings[0] = ((INodeData_SMB_COMPUTER)pNode.NodeData).ComputerName;
                        pNode.DisplayStrings[1] = ((INodeData_SMB_COMPUTER)pNode.NodeData).ComputerComment;
                        pNode.DefaultImageIndex = 7;
                    } break;
            }
        }
    }
}
